package top.zsyle.sycc.service.impl;

import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.terms.ParsedStringTerms;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;
import top.zsyle.sycc.doc.CourseDoc;
import top.zsyle.sycc.dto.CourseSearchDto;
import top.zsyle.sycc.repository.EsCourseRepository;
import top.zsyle.sycc.result.PageList;
import top.zsyle.sycc.service.IEsCourseService;
import top.zsyle.sycc.utils.EsPageList;
import top.zsyle.sycc.utils.HighlightResultMapper;
import org.springframework.util.StringUtils;
import top.zsyle.sycc.vo.AggResultVo;
import top.zsyle.sycc.vo.CourseAggResultVo;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class IEsCourseServiceImpl implements IEsCourseService {

    @Autowired
    private EsCourseRepository esCourseRepository;

    @Autowired
    private ElasticsearchRestTemplate elasticsearchRestTemplate;

    @Autowired
    private HighlightResultMapper highlightResultMapper;
    @Autowired
    private EsCourseRepository courseRepository;

    @Override
    public void save(CourseDoc courseDoc) {
        CourseDoc save = esCourseRepository.save(courseDoc);
        System.out.println(save);
    }

    @Override
    public PageList<CourseDoc> search(CourseSearchDto courseSearchDto) {
        String chargeName = courseSearchDto.getChargeName();
        Long courseTypeId = courseSearchDto.getCourseTypeId();
        String gradeName = courseSearchDto.getGradeName();
        String keyword = courseSearchDto.getKeyword();
        BigDecimal priceMax = courseSearchDto.getPriceMax();
        BigDecimal priceMin = courseSearchDto.getPriceMin();
        Integer rows = courseSearchDto.getRows();
        String sortField = courseSearchDto.getSortField();
        String sortType = courseSearchDto.getSortType();
        Integer page = courseSearchDto.getPage();

        NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();

        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        // 设置分词查询课程名称
        if (!StringUtils.isEmpty(keyword)){
            boolQueryBuilder.must(QueryBuilders.matchQuery("name", keyword.trim()));
        }
        // 设置课程类型查询
        if (!StringUtils.isEmpty(courseTypeId)){
            boolQueryBuilder.filter(QueryBuilders.termQuery("courseTypeId", courseTypeId));
        }
        // 设置课程等级查询
        if (!StringUtils.isEmpty(gradeName)){
            boolQueryBuilder.filter(QueryBuilders.termQuery("gradeName", gradeName));
        }

        // 设置课程支付方式查询
        if (!StringUtils.isEmpty(chargeName)){
            boolQueryBuilder.filter(QueryBuilders.termQuery("chargeName", chargeName));
        }

        // 设置价格区间查询
        if (!StringUtils.isEmpty(priceMin)){
            boolQueryBuilder.filter(QueryBuilders.rangeQuery("price").gte(priceMin));
        }

        // 设置价格区间查询
        if (!StringUtils.isEmpty(priceMax)){
            boolQueryBuilder.filter(QueryBuilders.rangeQuery("price").lte(priceMax));
        }


        nativeSearchQueryBuilder.withQuery(boolQueryBuilder);

        // 设置高亮
        nativeSearchQueryBuilder.withHighlightFields(new HighlightBuilder.Field("name").preTags("<span style='color:red'>").postTags("</span>"));

        // 设置排序
        if (!StringUtils.isEmpty(sortField) && !StringUtils.isEmpty(sortType)){
            SortOrder sortOrder = "asc".equals(sortType) ? SortOrder.ASC : SortOrder.DESC;
            nativeSearchQueryBuilder.withSort(SortBuilders.fieldSort(sortField).order(sortOrder));
        }
        // 设置分页
        nativeSearchQueryBuilder.withPageable(PageRequest.of(page, rows));

        // 给等级和是否收费进行聚合
        nativeSearchQueryBuilder.addAggregation(AggregationBuilders.terms("gradeNameTermsAgg").field("gradeName"));
        nativeSearchQueryBuilder.addAggregation(AggregationBuilders.terms("chargeNameTermsAgg").field("chargeName"));

        // 得到返回值结果，不玩高亮聚合可以这样写
        // Page<CourseDoc> pageResultTmp = courseRepository.search(nativeSearchQueryBuilder.build());
        AggregatedPage<CourseDoc> aggregatedPage = elasticsearchRestTemplate.queryForPage(nativeSearchQueryBuilder.build(), CourseDoc.class, highlightResultMapper);

        // 得到聚合结果
        Aggregations aggregations = aggregatedPage.getAggregations();
        Map<String, Aggregation> asMap = aggregations.getAsMap();


        AggResultVo aggResultVo = new AggResultVo();
        Map<String, List<CourseAggResultVo>> map = new HashMap<>();
        asMap.entrySet().forEach(e->{
            String key = e.getKey();
            List<? extends Terms.Bucket> buckets = ((ParsedStringTerms) e.getValue()).getBuckets();
            List<CourseAggResultVo> aggs = new ArrayList<>();
            buckets.forEach(b->{
                Object chargeKey = b.getKey();
                long docCount = b.getDocCount();
                CourseAggResultVo courseAggResultVo = new CourseAggResultVo(chargeKey.toString(), docCount);
                aggs.add(courseAggResultVo);
            });
            map.put(key, aggs);
//            if ("chargeNameTermsAgg".equals(key)){
//                List<CourseAggResultVo> chargeNameTermsAgg = new ArrayList<>();
//                buckets.forEach(b->{
//                    Object chargeKey = b.getKey();
//                    long docCount = b.getDocCount();
//                    CourseAggResultVo courseAggResultVo = new CourseAggResultVo(chargeKey.toString(), docCount);
//                    chargeNameTermsAgg.add(courseAggResultVo);
//                });
//                aggResultVo.setChargeNameTermsAgg(chargeNameTermsAgg);
//            }else if ("gradeNameTermsAgg".equals(key)){
//                List<CourseAggResultVo> gradeNameTermsAgg = new ArrayList<>();
//                buckets.forEach(b->{
//                    Object chargeKey = b.getKey();
//                    long docCount = b.getDocCount();
//                    CourseAggResultVo courseAggResultVo = new CourseAggResultVo(chargeKey.toString(), docCount);
//                    gradeNameTermsAgg.add(courseAggResultVo);
//                });
//                aggResultVo.setGradeNameTermsAgg(gradeNameTermsAgg);
//            }
        });


        return new EsPageList(aggregatedPage.getTotalElements(), aggregatedPage.getContent(), map);
    }
}
